bitkeeper revision 1.748.1.1 (403cc0a2uogkgkA4n8xi9XH9sph-GQ)
authormwilli2@equilibrium.research.intel-research.net <mwilli2@equilibrium.research.intel-research.net>
Wed, 25 Feb 2004 15:34:58 +0000 (15:34 +0000)
committermwilli2@equilibrium.research.intel-research.net <mwilli2@equilibrium.research.intel-research.net>
Wed, 25 Feb 2004 15:34:58 +0000 (15:34 +0000)
Add support for setting the trace buffer size as a boot parameter, for
returning the trace buffer size to user space and dynamically determining the
number of CPUs to map in xentrace.

docs/Xeno-HOWTO.txt
tools/xentrace/xentrace.c
xen/common/dom0_ops.c
xen/common/kernel.c
xen/common/trace.c
xen/include/hypervisor-ifs/dom0_ops.h
xen/include/xeno/trace.h

index e30c74794d816c3043f04ed9e7dc90e217ed2d84..9a74bbd7495421be48ea61ba187103272c0018d1 100644 (file)
@@ -225,6 +225,10 @@ The following is a list of command line arguments to pass to Xen:
 
  dom0_mem=xxx     Set the maximum amount of memory for domain0.
 
+ tbuf_size=xxx    Set the size of the per-cpu trace buffers, in pages
+                  (default 1).  Note that the trace buffers are only
+                  enabled in debug builds.  Most users can ignore
+                  this feature completely.
 
 Boot into Domain 0
 ==============================
index 526c8152fc8b99c629c88c1e61353bc6cd9498bc..8ac48331ffb722acff788ed4450f690cd28ba401 100644 (file)
 
 extern FILE *stdout;
 
-/***** Compile time configuration of defaults ********************************/
 
-#define NUM_CPUS 1 /* XXX this ought to be removed and replaced with something
-                    * cleverer to dynamically query the machine - I'll use a
-                    * dom0 op once I've implemented it! :-) */
+/***** Compile time configuration of defaults ********************************/
 
 /* when we've got more records than this waiting, we log it to the output */
 #define NEW_DATA_THRESH 1
@@ -39,11 +36,11 @@ extern FILE *stdout;
 /* sleep for this long (milliseconds) between checking the trace buffers */
 #define POLL_SLEEP_MILLIS 100
 
+
 /***** The code **************************************************************/
 
 typedef struct settings_st {
     char *outfile;
-    unsigned int num_cpus;
     struct timespec poll_sleep;
     unsigned long new_data_thresh;
 } settings_t;
@@ -90,13 +87,14 @@ void print_rec(unsigned int cpu, struct t_rec *rec, FILE *out)
 
 
 /**
- * get_tbuf_ptrs - get pointer to trace buffers
+ * get_tbufs - get pointer to and size of the trace buffers
+ * @phys_addr: location to store physical address if the trace buffers to
+ * @size:      location to store the size of a trace buffer to
  *
- * Does a dom0 op to fetch a "pointer" to the trace buffers.  The pointer can't
- * be dereferenced immediately, since it is a physical address of memory in Xen
- * space - they are used in this program to mmap the right area from /dev/mem.
+ * Gets the physical address of the trace pointer area and the size of the
+ * per CPU buffers.
  */
-unsigned long get_tbuf_ptrs(void)
+void get_tbufs(unsigned long *phys_addr, unsigned long *size)
 {
     int ret;
     dom0_op_t op;                        /* dom0 op we'll build             */
@@ -114,22 +112,29 @@ unsigned long get_tbuf_ptrs(void)
         PERROR("Failure to get trace buffer pointer from Xen");
         exit(EXIT_FAILURE);
     }
-    
-    return op.u.gettbufs.phys_addr;
+
+    *phys_addr = op.u.gettbufs.phys_addr;
+    *size      = op.u.gettbufs.size;
 }
 
 /**
  * map_tbufs - memory map Xen trace buffers into user space
  * @tbufs:     physical address of the trace buffers
+ * @num:       number of trace buffers to map
+ * @size:      size of each trace buffer
  *
- * Given the physical address of the Xen trace buffers, maps them into process
- * address space by memory mapping /dev/mem.  Returns a pointer to the location
- * the buffers have been mapped to.
+ * Maps the Xen trace buffers them into process address space by memory mapping
+ * /dev/mem.  Returns the location the buffers have been mapped to.
  */
-struct t_buf *map_tbufs(unsigned long tbufs_phys)
+struct t_buf *map_tbufs(unsigned long tbufs_phys, unsigned int num,
+                        unsigned long size)
 {
-    int dm_fd;                    /* file descriptor for /dev/mem */
+    int dm_fd;                               /* file descriptor for /dev/mem */
     struct t_buf *tbufs_mapped;
+    unsigned int page_size = getpagesize();
+    unsigned int off_in_pg = (tbufs_phys % page_size);
+
+    tbufs_phys -= off_in_pg; /* correct tbufs_phys if not page-aligned */
 
     dm_fd = open("/dev/mem", O_RDONLY);
     if ( dm_fd < 0 ) 
@@ -137,8 +142,8 @@ struct t_buf *map_tbufs(unsigned long tbufs_phys)
         PERROR("Open /dev/mem when mapping trace buffers\n");
         exit(EXIT_FAILURE);
     }
-    
-    tbufs_mapped = (struct t_buf *)mmap(NULL, opts.num_cpus * TB_SIZE,
+
+    tbufs_mapped = (struct t_buf *)mmap(NULL, size * num + off_in_pg,
                                         PROT_READ, MAP_SHARED,
                                         dm_fd, (off_t)tbufs_phys);
 
@@ -149,24 +154,28 @@ struct t_buf *map_tbufs(unsigned long tbufs_phys)
         PERROR("Failed to mmap trace buffers");
         exit(EXIT_FAILURE);
     }
-    
-    return tbufs_mapped;
+
+    /* add offset to get buffers in case original address wasn't pg aligned */
+    return (struct t_buf *)((unsigned long)tbufs_mapped + off_in_pg);
 }
 
 
 /**
  * init_bufs_ptrs - initialises an array of pointers to the trace buffers
  * @bufs_mapped:    the userspace address where the trace buffers are mapped
+ * @num:            number of trace buffers
+ * @size:           trace buffer size
  *
  * Initialises an array of pointers to individual trace buffers within the
  * mapped region containing all trace buffers.
  */
-struct t_buf **init_bufs_ptrs(void *bufs_mapped)
+struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
+                              unsigned long size)
 {
     int i;
     struct t_buf **user_ptrs;
 
-    user_ptrs = (struct t_buf **)calloc(opts.num_cpus, sizeof(struct t_buf *));
+    user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *));
     if ( user_ptrs == NULL )
     {
         PERROR( "Failed to allocate memory for buffer pointers\n");
@@ -175,9 +184,9 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped)
     
     /* initialise pointers to the trace buffers - given the size of a trace
      * buffer and the value of bufs_maped, we can easily calculate these */
-    for ( i = 0; i<opts.num_cpus; i++ )
+    for ( i = 0; i<num; i++ )
         user_ptrs[i] = (struct t_buf *)(
-            (unsigned long)bufs_mapped + TB_SIZE * i);
+            (unsigned long)bufs_mapped + size * i);
 
     return user_ptrs;
 }
@@ -188,6 +197,7 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped)
  * @tbufs_phys:    physical base address of the trace buffer area
  * @tbufs_mapped:  user virtual address of base of trace buffer area
  * @meta:          array of user-space pointers to struct t_buf's of metadata
+ * @num:           number of trace buffers
  *
  * Initialises data area pointers to the locations that data areas have been
  * mapped in user space.  Note that the trace buffer metadata contains physical
@@ -195,19 +205,20 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped)
  */
 struct t_rec **init_rec_ptrs(unsigned long tbufs_phys,
                              struct t_buf *tbufs_mapped,
-                             struct t_buf **meta)
+                             struct t_buf **meta,
+                             unsigned int num)
 {
     int i;
     struct t_rec **data;
     
-    data = calloc(opts.num_cpus, sizeof(struct t_rec *));
+    data = calloc(num, sizeof(struct t_rec *));
     if ( data == NULL )
     {
         PERROR("Failed to allocate memory for data pointers\n");
         exit(EXIT_FAILURE);
     }
 
-    for ( i = 0; i<opts.num_cpus; i++ )
+    for ( i = 0; i<num; i++ )
         data[i] = (struct t_rec *)((unsigned long)meta[i]->data -
                                    tbufs_phys + (unsigned long)tbufs_mapped);
 
@@ -216,16 +227,17 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_phys,
 
 /**
  * init_tail_idxs - initialise an array of tail indexes
- * @bufs:           array of pointers to trace buffer metadata in struct t_buf's
+ * @bufs:           array of pointers to trace buffer metadata
+ * @num:            number of trace buffers
  *
  * The tail indexes indicate where we're read to so far in the data array of a
  * trace buffer.  Each entry in this table corresponds to the tail index for a
  * particular trace buffer.
  */
-int *init_tail_idxs(struct t_buf **bufs)
+int *init_tail_idxs(struct t_buf **bufs, unsigned int num)
 {
     int i;
-    int *tails = calloc(opts.num_cpus, sizeof(unsigned int));
+    int *tails = calloc(num, sizeof(unsigned int));
  
     if ( tails == NULL )
     {
@@ -233,12 +245,37 @@ int *init_tail_idxs(struct t_buf **bufs)
         exit(EXIT_FAILURE);
     }
     
-    for ( i = 0; i<opts.num_cpus; i++ )
+    for ( i = 0; i<num; i++ )
         tails[i] = bufs[i]->head;
 
     return tails;
 }
 
+/**
+ * get_num_cpus - get the number of logical CPUs
+ */
+unsigned int get_num_cpus()
+{
+    dom0_op_t op;
+    int xc_handle = xc_interface_open();
+    int ret;
+    
+    op.cmd = DOM0_PHYSINFO;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+
+    ret = do_dom0_op(xc_handle, &op);
+    
+    if ( ret != 0 )
+    {
+        PERROR("Failure to get logical CPU count from Xen");
+        exit(EXIT_FAILURE);
+    }
+
+    xc_interface_close(xc_handle);
+
+    return op.u.physinfo.ht_per_core * op.u.physinfo.cores;
+}
+
 
 /**
  * monitor_tbufs - monitor the contents of tbufs and output to a file
@@ -253,20 +290,25 @@ int monitor_tbufs(FILE *logfile)
                                   * where they are mapped into user space.   */
     int *tails;                  /* store tail indexes for the trace buffers */
     unsigned long tbufs_phys;    /* physical address of the tbufs            */
-    
+    unsigned int  num;           /* number of trace buffers / logical CPUS   */
+    unsigned long size;          /* size of a single trace buffer            */
+
+    /* get number of logical CPUs (and therefore number of trace buffers) */
+    num = get_num_cpus();
+
     /* setup access to trace buffers */
-    tbufs_phys   = get_tbuf_ptrs();
-    tbufs_mapped = map_tbufs(tbufs_phys);
+    get_tbufs(&tbufs_phys, &size);
+    tbufs_mapped = map_tbufs(tbufs_phys, num, size);
 
     /* build arrays of convenience ptrs */
-    meta  = init_bufs_ptrs (tbufs_mapped);
-    data  = init_rec_ptrs  (tbufs_phys, tbufs_mapped, meta);
-    tails = init_tail_idxs (meta);
+    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
+    data  = init_rec_ptrs  (tbufs_phys, tbufs_mapped, meta, num);
+    tails = init_tail_idxs (meta, num);
 
     /* now, scan buffers for events */
     while ( !interrupted )
     {
-        for ( i = 0; i < opts.num_cpus; i++ )
+        for ( i = 0; ( i < num ) && !interrupted; i++ )
         {
             signed long newdata = meta[i]->head - tails[i];
             signed long prewrap = newdata;
@@ -335,15 +377,6 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state)
             argp_usage(state);
     }
     break;
-
-    case 'n': /* set number of CPU trace buffers to map */
-    {
-        char *inval;
-        setup->num_cpus = strtol(arg, &inval, 0);
-        if (inval == arg )
-            argp_usage(state);
-    }
-    break;
     
     case ARGP_KEY_ARG:
     {
@@ -376,11 +409,6 @@ const struct argp_option cmd_opts[] =
       "Set sleep time, p, in milliseconds between polling the trace buffer "
       "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." },
 
-    { .name = "num-cpus", .key = 'n', .arg="i",
-      .doc = 
-      "Set number, i, of CPU trace buffers to map.  This should not exceed "
-      "the number of CPUs in the system (default " xstr(NUM_CPUS) ")." },
-
     {0}
 };
 
@@ -399,7 +427,7 @@ const struct argp parser_def =
 };
 
 
-const char *argp_program_version     = "xentrace v1.0";
+const char *argp_program_version     = "xentrace v1.1";
 const char *argp_program_bug_address = "<mark.a.williamson@intel.com>";
         
     
@@ -411,7 +439,6 @@ int main(int argc, char **argv)
     const struct sigaction act = { .sa_handler = close_handler };
 
     opts.outfile = 0;
-    opts.num_cpus = 1;
     opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS);
     opts.new_data_thresh = NEW_DATA_THRESH;
 
index ab81ca662cf1a6ecd2c1ecaf69276a939d3c4296..6f829e135a64b3861ca7285f1784f1bde9c0af22 100644 (file)
@@ -436,9 +436,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
 #ifdef TRACE_BUFFER
     case DOM0_GETTBUFS:
     {
-       op->u.gettbufs.phys_addr = get_tb_ptr();
+        ret = get_tb_info(&op->u.gettbufs);
        copy_to_user(u_dom0_op, op, sizeof(*op));
-       ret = 0;
     }
     break;
 #endif
index b113f2c8123ff23ca2d24667686fccf5153b5393..3f1d0fd24c4c871fd33f221387191a2af2587ca4 100644 (file)
@@ -77,6 +77,8 @@ int opt_ignorebiostables=0;
 int opt_watchdog=0;
 /* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */
 unsigned char opt_pdb[10] = "none";
+/* opt_tbuf_size: trace buffer size (in pages) */
+unsigned int opt_tbuf_size = 1;
 
 static struct {
     unsigned char *name;
@@ -96,6 +98,7 @@ static struct {
     { "ignorebiostables", OPT_BOOL, &opt_ignorebiostables },
     { "watchdog",         OPT_BOOL, &opt_watchdog },
     { "pdb",              OPT_STR,  &opt_pdb },
+    { "tbuf_size",        OPT_UINT, &opt_tbuf_size },
     { NULL,               0,        NULL     }
 };
 
index 9a1d4556315d749a5ed22676f73b231b767136e5..aa2e7b949fd91671a265346bb1b7c3c402d40e17 100644 (file)
@@ -29,7 +29,9 @@
 #include <xeno/smp.h>
 #include <xeno/spinlock.h>
 #include <xeno/trace.h>
+#include <xeno/errno.h>
 #include <asm/atomic.h>
+#include <hypervisor-ifs/dom0_ops.h>
 
 /* Pointers to the meta-data objects for all system trace buffers */
 struct t_buf *t_bufs[NR_CPUS];
@@ -46,11 +48,20 @@ int tb_init_done = 0;
  */
 void init_trace_bufs(void)
 {
+    extern int opt_tbuf_size;
+
     int           i;
     char         *rawbuf;
     struct t_buf *buf;
+    
+    if ( opt_tbuf_size == 0 )
+    {
+        printk("Xen trace buffers: disabled\n");
+        return;
+    }
 
-    if ( (rawbuf = kmalloc(smp_num_cpus * TB_SIZE, GFP_KERNEL)) == NULL )
+    if ( (rawbuf = kmalloc(smp_num_cpus * opt_tbuf_size * PAGE_SIZE,
+                           GFP_KERNEL)) == NULL )
     {
         printk("Xen trace buffers: memory allocation failed\n");
         return;
@@ -58,7 +69,7 @@ void init_trace_bufs(void)
     
     for ( i = 0; i < smp_num_cpus; i++ )
     {
-        buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*TB_SIZE];
+        buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*opt_tbuf_size*PAGE_SIZE];
         
         /* For use in Xen. */
         buf->vdata    = (struct t_rec *)(buf+1);
@@ -70,7 +81,8 @@ void init_trace_bufs(void)
         buf->head = 0;
 
         /* For use in both. */
-        buf->size = (TB_SIZE - sizeof(struct t_buf)) / sizeof(struct t_rec);
+        buf->size = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf))
+                                                        / sizeof(struct t_rec);
     }
 
     printk("Xen trace buffers: initialised\n");
@@ -81,15 +93,29 @@ void init_trace_bufs(void)
 }
 
 /**
- * get_tb_ptr - return physical address of the trace buffers.
+ * get_tb_info - get trace buffer details
+ * @st: a pointer to a dom0_gettbufs_t to be filled out
  *
  * Called by the %DOM0_GETTBUFS dom0 op to fetch the physical address of the
  * trace buffers.
  */
-unsigned long get_tb_ptr(void)
+int get_tb_info(dom0_gettbufs_t *st)
 {
-    /* Return the physical address. */
-    return __pa(t_bufs[0]);
+    if(tb_init_done)
+    {
+        extern unsigned int opt_tbuf_size;
+        
+        st->phys_addr = __pa(t_bufs[0]);
+        st->size      = opt_tbuf_size * PAGE_SIZE;
+        
+        return 0;
+    }
+    else
+    {
+        st->phys_addr = 0;
+        st->size      = 0;
+        return -ENODATA;
+    }
 }
 
 #endif /* TRACE_BUFFER */
index 5e0abe6295a4097145f12f80cf3ae605f89ae2d3..5e47e64c0e59a885b41f8c2b869affbed16e614a 100644 (file)
@@ -17,7 +17,7 @@
  * This makes sure that old versions of dom0 tools will stop working in a
  * well-defined way (rather than crashing the machine, for instance).
  */
-#define DOM0_INTERFACE_VERSION   0xAAAA0007
+#define DOM0_INTERFACE_VERSION   0xAAAA0008
 
 /*
  * The following is all CPU context. Note that the i387_ctxt block is filled 
@@ -213,8 +213,9 @@ typedef struct dom0_pincpudomain_st
 #define DOM0_GETTBUFS         21
 typedef struct dom0_gettbufs_st
 {
-  /* OUT variable - location of the trace buffers */
-  unsigned long phys_addr;
+  /* OUT variables */
+  unsigned long phys_addr; /* location of the trace buffers       */
+  unsigned long size;      /* size of each trace buffer, in bytes */
 } dom0_gettbufs_t;
 
 /*
index aa7ba5121c9a42b1e7aea235dc9b7268c0656d28..9268145905fa8908002792b2a99ceba086b6501a 100644 (file)
 #ifndef __XENO_TRACE_H__
 #define __XENO_TRACE_H__
 
-/*
- * How much space is allowed for a single trace buffer, including data and
- * metadata (and maybe some waste).
- */
-#define TB_SIZE PAGE_SIZE
-
 /* This structure represents a single trace buffer record. */
 struct t_rec {
     u64 cycles;               /* 64 bit cycle counter timestamp */
@@ -63,12 +57,13 @@ struct t_buf {
 #include <asm/atomic.h>
 #include <asm/current.h>
 #include <asm/msr.h>
+#include <hypervisor-ifs/dom0_ops.h>
 
 /* Used to initialise trace buffer functionality */
 void init_trace_bufs(void);
 
 /* used to retrieve the physical address of the trace buffers */
-struct t_buf *get_tb_ptr(void);
+int get_tb_info(dom0_gettbufs_t *st);
 
 /**
  * trace - Enters a trace tuple into the trace buffer for the current CPU.